----------------------------------------------------------------------------------
-- CPEG 422 spartan-3e base
-- Jason Parrott
-- Rodney McGee
-- Ray Delvecchio
-- Juergen Ributzka
-- Jack Welsh
-- Ryan Hoover
-- Mike Stamat
-- Lee Reed
--
-- Crypto System
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity crypto_top is
    Port ( clk     : in  STD_LOGIC;
           reset   : in  STD_LOGIC;
			  ed      : in STD_LOGIC;
		  	  i_ready : in STD_LOGIC;
			  din     : in STD_LOGIC_VECTOR (127 downto 0);
			  dout    : out STD_LOGIC_VECTOR (127 downto 0);
			  o_ready : out  STD_LOGIC);
end crypto_top;

architecture crypto_top_arch of crypto_top is

signal LFSR: std_logic_vector(95 downto 0);
signal LFSR_ready: std_logic;

signal pre_crypto : std_logic_vector(95 downto 0);
signal post_crypto : std_logic_vector(95 downto 0);

signal buffer_128 : std_logic_vector(127 downto 0);

signal six_bit_ascii : std_logic_vector(5 downto 0);
signal eight_bit_ascii : std_logic_vector(7 downto 0);

type statetype is (S0, S1, S11, S12, S2, S21, S3, S31, S32, S4, S41);
signal state, next_state : statetype := S0;

begin

state <= next_state;

process (clk, reset) is

variable ctr: STD_LOGIC_VECTOR (3 downto 0); 

begin
		if (reset = '1') then
			o_ready <= '0';
			dout <= x"00000000000000000000000000000000";
			
			pre_crypto  <= x"000000000000000000000000";
			post_crypto <= x"000000000000000000000000";
			
			buffer_128 <= x"00000000000000000000000000000000";
			ctr := x"0";
			
			six_bit_ascii <= "000000";
			eight_bit_ascii <= "00000000";
			
			next_state <= S0;
		elsif (rising_edge(clk)) then
				
			case state is

			-- Wait for our input to be ready!
			when S0 =>
				if (i_ready = '1') then
					buffer_128 <= din;
					next_state <= S1;
				else
					next_state <= S0;
				end if;
			
			-- Convert from 128 bit ascii to our format
			when S1 =>
				case buffer_128(127 downto 120) is
					when x"30" => six_bit_ascii <= "000001"; --0
					when x"31" => six_bit_ascii <= "000010"; --1
					when x"32" => six_bit_ascii <= "000011"; --2
					when x"33" => six_bit_ascii <= "000100"; --3
					when x"34" => six_bit_ascii <= "000101"; --4
					when x"35" => six_bit_ascii <= "000110"; --5
					when x"36" => six_bit_ascii <= "000111"; --6
					when x"37" => six_bit_ascii <= "001000"; --7
					when x"38" => six_bit_ascii <= "001001"; --8
					when x"39" => six_bit_ascii <= "001010"; --9
					when x"41" => six_bit_ascii <= "001011"; --A
					when x"42" => six_bit_ascii <= "001100"; --B
					when x"43" => six_bit_ascii <= "001101"; --C
					when x"44" => six_bit_ascii <= "001111"; --D
					when x"45" => six_bit_ascii <= "010000"; --E
					when x"46" => six_bit_ascii <= "010001"; --F
					when x"47" => six_bit_ascii <= "010010"; --G
					when x"48" => six_bit_ascii <= "010011"; --H
					when x"49" => six_bit_ascii <= "010100"; --I
					when x"4A" => six_bit_ascii <= "010101"; --J
					when x"4B" => six_bit_ascii <= "010110"; --K
					when x"4C" => six_bit_ascii <= "010111"; --L
					when x"4D" => six_bit_ascii <= "011000"; --M
					when x"4E" => six_bit_ascii <= "011001"; --N
					when x"4F" => six_bit_ascii <= "011010"; --O
					when x"50" => six_bit_ascii <= "011011"; --P
					when x"51" => six_bit_ascii <= "011100"; --Q
					when x"52" => six_bit_ascii <= "011101"; --R
					when x"53" => six_bit_ascii <= "011110"; --S
					when x"54" => six_bit_ascii <= "011111"; --T
					when x"55" => six_bit_ascii <= "100000"; --U
					when x"56" => six_bit_ascii <= "100001"; --V
					when x"57" => six_bit_ascii <= "100010"; --W
					when x"58" => six_bit_ascii <= "100011"; --X
					when x"59" => six_bit_ascii <= "100100"; --Y
					when x"5A" => six_bit_ascii <= "100101"; --Z
					when x"61" => six_bit_ascii <= "100110"; --a
					when x"62" => six_bit_ascii <= "100111"; --b
					when x"63" => six_bit_ascii <= "101000"; --c
					when x"64" => six_bit_ascii <= "101001"; --d
					when x"65" => six_bit_ascii <= "101010"; --e
					when x"66" => six_bit_ascii <= "101011"; --f
					when x"67" => six_bit_ascii <= "101100"; --g
					when x"68" => six_bit_ascii <= "101101"; --h
					when x"69" => six_bit_ascii <= "101110"; --i
					when x"6A" => six_bit_ascii <= "101111"; --j
					when x"6B" => six_bit_ascii <= "110000"; --k
					when x"6C" => six_bit_ascii <= "110001"; --l
					when x"6D" => six_bit_ascii <= "110010"; --m
					when x"6E" => six_bit_ascii <= "110011"; --n
					when x"6F" => six_bit_ascii <= "110100"; --o
					when x"70" => six_bit_ascii <= "110101"; --p
					when x"71" => six_bit_ascii <= "110110"; --q
					when x"72" => six_bit_ascii <= "110111"; --r
					when x"73" => six_bit_ascii <= "111000"; --s
					when x"74" => six_bit_ascii <= "111001"; --t
					when x"75" => six_bit_ascii <= "111010"; --u
					when x"76" => six_bit_ascii <= "111011"; --v
					when x"77" => six_bit_ascii <= "111100"; --w
					when x"78" => six_bit_ascii <= "111101"; --x
					when x"79" => six_bit_ascii <= "111110"; --y
					when x"7A" => six_bit_ascii <= "111111"; --z
					when x"2d" => six_bit_ascii <= "001110"; ---
					when others => six_bit_ascii <= "000000"; --_
				end case;
				next_state <= S11;
				
			when S11 =>
				pre_crypto <= pre_crypto(89 downto 0) & six_bit_ascii;
				buffer_128 <= buffer_128(119 downto 0) & x"00";
				ctr := ctr + 1;
				next_state <= S12;
			
			when S12 =>
				if(ctr = x"0") then
					ctr := x"0";
					next_state <= S2;
				else
					next_state <= S1;
				end if;
			
			-- Perform cryption! - First wait for LFSR to be ready
			when S2 =>
				if LFSR_ready = '0' then
					next_state <= S2;
				else
					next_state <= S21;
				end if;
			
			when S21 =>
				post_crypto <= LFSR xor pre_crypto;
				next_state <= S3;
			
			-- Convert from our format to 128 bit ascii
			when S3 =>
				case post_crypto(95 downto 90) is
					when "000001" => eight_bit_ascii <= x"30"; --0
					when "000010" => eight_bit_ascii <= x"31"; --1
					when "000011" => eight_bit_ascii <= x"32"; --2
					when "000100" => eight_bit_ascii <= x"33"; --3
					when "000101" => eight_bit_ascii <= x"34"; --4
					when "000110" => eight_bit_ascii <= x"35"; --5
					when "000111" => eight_bit_ascii <= x"36"; --6
					when "001000" => eight_bit_ascii <= x"37"; --7
					when "001001" => eight_bit_ascii <= x"38"; --8
					when "001010" => eight_bit_ascii <= x"39"; --9
					when "001011" => eight_bit_ascii <= x"41"; --A
					when "001100" => eight_bit_ascii <= x"42"; --B
					when "001101" => eight_bit_ascii <= x"43"; --C
					when "001111" => eight_bit_ascii <= x"44"; --D
					when "010000" => eight_bit_ascii <= x"45"; --E
					when "010001" => eight_bit_ascii <= x"46"; --F
					when "010010" => eight_bit_ascii <= x"47"; --G
					when "010011" => eight_bit_ascii <= x"48"; --H
					when "010100" => eight_bit_ascii <= x"49"; --I
					when "010101" => eight_bit_ascii <= x"4A"; --J
					when "010110" => eight_bit_ascii <= x"4B"; --K
					when "010111" => eight_bit_ascii <= x"4C"; --L
					when "011000" => eight_bit_ascii <= x"4D"; --M
					when "011001" => eight_bit_ascii <= x"4E"; --N
					when "011010" => eight_bit_ascii <= x"4F"; --O
					when "011011" => eight_bit_ascii <= x"50"; --P
					when "011100" => eight_bit_ascii <= x"51"; --Q
					when "011101" => eight_bit_ascii <= x"52"; --R
					when "011110" => eight_bit_ascii <= x"53"; --S
					when "011111" => eight_bit_ascii <= x"54"; --T
					when "100000" => eight_bit_ascii <= x"55"; --U
					when "100001" => eight_bit_ascii <= x"56"; --V
					when "100010" => eight_bit_ascii <= x"57"; --W
					when "100011" => eight_bit_ascii <= x"58"; --X
					when "100100" => eight_bit_ascii <= x"59"; --Y
					when "100101" => eight_bit_ascii <= x"5A"; --Z
					when "100110" => eight_bit_ascii <= x"61"; --a
					when "100111" => eight_bit_ascii <= x"62"; --b
					when "101000" => eight_bit_ascii <= x"63"; --c
					when "101001" => eight_bit_ascii <= x"64"; --d
					when "101010" => eight_bit_ascii <= x"65"; --e
					when "101011" => eight_bit_ascii <= x"66"; --f
					when "101100" => eight_bit_ascii <= x"67"; --g
					when "101101" => eight_bit_ascii <= x"68"; --h
					when "101110" => eight_bit_ascii <= x"69"; --i
					when "101111" => eight_bit_ascii <= x"6A"; --j
					when "110000" => eight_bit_ascii <= x"6B"; --k
					when "110001" => eight_bit_ascii <= x"6C"; --l
					when "110010" => eight_bit_ascii <= x"6D"; --m
					when "110011" => eight_bit_ascii <= x"6E"; --n
					when "110100" => eight_bit_ascii <= x"6F"; --o
					when "110101" => eight_bit_ascii <= x"70"; --p
					when "110110" => eight_bit_ascii <= x"71"; --q
					when "110111" => eight_bit_ascii <= x"72"; --r
					when "111000" => eight_bit_ascii <= x"73"; --s
					when "111001" => eight_bit_ascii <= x"74"; --t
					when "111010" => eight_bit_ascii <= x"75"; --u
					when "111011" => eight_bit_ascii <= x"76"; --v
					when "111100" => eight_bit_ascii <= x"77"; --w
					when "111101" => eight_bit_ascii <= x"78"; --x
					when "111110" => eight_bit_ascii <= x"79"; --y
					when "111111" => eight_bit_ascii <= x"7A"; --z
					when "001110" => eight_bit_ascii <= x"2d"; ---
					when others => 
						if ed = '0' then
							eight_bit_ascii <= x"20";   -- Decoding - print space
						else
							eight_bit_ascii <= x"5f";   -- Encoding - print _
						end if;
				end case;
				next_state <= S31;
				
			when S31 =>
				buffer_128 <= buffer_128(119 downto 0) & eight_bit_ascii;
				post_crypto <= post_crypto(89 downto 0) & "000000";
				ctr := ctr + 1;
				next_state <= S32;
			
			when S32 =>
				if(ctr = x"0") then
					ctr := x"0";
					next_state <= S4;
				else
					next_state <= S3;
				end if;
				
			-- And we clean up
			when S4 =>
				dout <= buffer_128;
				o_ready <= '1';
				next_state <= S41;
			
			when S41 =>
				if i_ready = '0' then
					o_ready <= '0';
					next_state <= S0;
				else
					next_state <= S41;
				end if;
				  
			end case;
		
		end if;
end process;

-----------------------------
-- Process for computing LFSR
-----------------------------
process (clk, reset) is
variable ctr: STD_LOGIC_VECTOR (7 downto 0);
begin
	if (reset = '1') then
		LFSR         <= x"E2309E3975AB097F09752BB0";
		LFSR_ready   <= '0';
		ctr := x"00";
	elsif (rising_edge(clk)) then
		if LFSR_ready = '0' then
			if ctr = x"60" then
				LFSR_ready <= '1';
			else
				LFSR <= LFSR(94 downto 0) & (LFSR(15) xor LFSR(11) xor LFSR(0));
				ctr := ctr + 1;
			end if;
		end if;		
	end if;
end process;

end crypto_top_arch;

